; =================================
; ========== NMI-RUTIINI ==========
; =================================

NMIcode:

; Skrollaus.
	lda ScrollValueDelay
	eor #%00000001
	sta ScrollValueDelay
	cmp #00
	beq SkrollausTehty	; Skrollaus vain joka toisella VBlankilla, ei tll.
	lda ScrollValue
	cmp #00			; ScrollValuen pit olla 0 - 239, kun se kirjoitetaan $2005:een.
	bne PienennaScrollValueta
	lda #240
	sta ScrollValue
PienennaScrollValueta:
	dec ScrollValue
	lda ScrollValue
	ldx #00
	stx $2005
	sta $2005
; Joka 16. skrollauspikselill eli joka 32. VBlankilla suurennetaan VihKarttaLaskuria.
	lda ScrollValue
	and #%00001111
	cmp #00
	bne SkrollausTehty

	inc VihKarttaLaskuri
; Tutkitaan VihollisDatan 1. tavu. Listn vihollinen, jos tavu <> 00.
	lda VihKarttaLaskuri
	asl a
	tax
	dex
	dex				; Nyt X = 2 * VihKarttaLaskuri - 2.
	lda VihollisData,x
	cmp #$FF
	bne DatatEivatOleLopussa
	lda #00			; VihollisDatat loppuivat. Nollataan VihKarttaLaskuri.
	sta VihKarttaLaskuri
	jmp SkrollausTehty
DatatEivatOleLopussa:
	cmp #00
	beq SkrollausTehty	; Jos VihollisData = 00.

	jsr LisaaVihollinen	; Lis vihollinen VihollisDatan ilmoittamaan X-koordinaattiin (A-rekisteriss).
; Tutkitaan VihollisDatan 2. tavu. (Vain, jos 1. tavu oli muu kuin 00 tai $FF.)
	lda VihKarttaLaskuri
	asl a
	tax
	dex				; Nyt X = 2 * VihKarttaLaskuri - 1.
	lda VihollisData,x
	cmp #00
	beq SkrollausTehty

	jsr LisaaVihollinen
SkrollausTehty:

; Oman koneen moottoriliekin animointi (spritet $3E ja $3F).
	inc LiekkiTimer	; Voi vaihdella 0 - 255.
	lda LiekkiTimer
	and #%00000011	; Joka 4. framella vaihdetaan spriten tiilt.
	bne LiekkiEiVaihdu
	ldx #01
	lda Sprite_liekki,x
	eor #%00000001
	sta Sprite_liekki,x
LiekkiEiVaihdu:

; Lue nppimet ja liikuta konetta vasemmalle tai oikealle.
	jsr ReadJoypad

; Kasvata ajastimen lukemaa, jos se ei ole FiringRate.
	lda GunTimer
	cmp FiringRate
	bpl AlaKasvataAjastinta
	inc GunTimer
AlaKasvataAjastinta:

; Ammu, jos B:t painetaan JA GunTimer = FiringRate.
	lda Keystate
	and #%01000000
	beq EiAmmuta
	lda GunTimer
	cmp FiringRate
	bmi EiAmmuta
	jsr Shoot
	lda #00
	sta GunTimer
EiAmmuta:

; Onko ylnuolta painettu.
	lda Keystate
	and #%00001000
	beq EiYlaaPainettu
	jsr MoveUp
	jsr MoveUp
EiYlaaPainettu:

; Onko alanuolta painettu.
	lda Keystate
	and #%00000100
	beq EiAlaaPainettu
	jsr MoveDown
	jsr MoveDown
EiAlaaPainettu:

; Onko vasenta nuolta painettu.
	lda Keystate
	and #%00000010
	beq EiVasentaPainettu
	jsr MoveLeft
	jsr MoveLeft
; Kaikkien spritejen peilaukset pois.
	ldx #02	; Attribuutit = perusosoite + 2.
	lda #%00100000
	sta Sprite_omakone1,x
	sta Sprite_omakone2,x
	sta Sprite_omakone3,x
	sta Sprite_omakone4,x
	sta Sprite_omakone5,x
	sta Sprite_omakone6,x
	sta Sprite_omakone7,x
; Vaihdetaan kaikki spritet toisiksi.
	ldx #01	; Tiilen numero = perusosoite + 1.
	lda #09
	sta Sprite_omakone1,x
	lda #$0A
	sta Sprite_omakone2,x
	lda #$0B
	sta Sprite_omakone3,x
	lda #$0C
	sta Sprite_omakone4,x
	lda #$0D
	sta Sprite_omakone5,x
	lda #$0E
	sta Sprite_omakone6,x
	lda #$0F
	sta Sprite_omakone7,x
EiVasentaPainettu:

; Onko oikeata nuolta painettu.
	lda Keystate
	and #%00000001
	beq EiOikeataPainettu
	jsr MoveRight
	jsr MoveRight
; Kaikkien spritejen peilaukset plle.
	ldx #02	; Attribuutit = perusosoite + 2.
	lda #%01100000
	sta Sprite_omakone1,x
	sta Sprite_omakone2,x
	sta Sprite_omakone3,x
	sta Sprite_omakone4,x
	sta Sprite_omakone5,x
	sta Sprite_omakone6,x
	sta Sprite_omakone7,x
; Vaihdetaan kaikki spritet toisiksi.
	ldx #01	; Tiilen numero = perusosoite + 1.
	lda #09
	sta Sprite_omakone1,x
	lda #$0C
	sta Sprite_omakone2,x
	lda #$0B
	sta Sprite_omakone3,x
	lda #$0A
	sta Sprite_omakone4,x
	lda #$0F
	sta Sprite_omakone5,x
	lda #$0E
	sta Sprite_omakone6,x
	lda #$0D
	sta Sprite_omakone7,x
EiOikeataPainettu:


; Onko kumpaakaan nuolta painettu.
	lda Keystate
	and #%00000011
	bne KoneOnLiikkeessa
; Spritejen 4 ja 7 peilaus plle, muitten pois.
	ldx #02	; Attribuutit = perusosoite + 2.
	lda #%00100000
	sta Sprite_omakone1,x
	sta Sprite_omakone2,x
	sta Sprite_omakone3,x
	sta Sprite_omakone5,x
	sta Sprite_omakone6,x
	lda #%01100000
	sta Sprite_omakone4,x
	sta Sprite_omakone7,x
; Vaihdetaan kaikki spritet toisiksi.
	ldx #01	; Tiilen numero = perusosoite + 1.
	lda #04
	sta Sprite_omakone1,x
	lda #07
	sta Sprite_omakone2,x
	lda #05
	sta Sprite_omakone3,x
	lda #07
	sta Sprite_omakone4,x
	lda #08
	sta Sprite_omakone5,x
	lda #06
	sta Sprite_omakone6,x
	lda #08
	sta Sprite_omakone7,x
KoneOnLiikkeessa:

; Luetaan vihollisten koordinaatit muuttujiin VihX1, VihX2 jne.
	ldy #00
VihKoordLukuLoop:
; X = Y * 4.
	tya
	asl a
	asl a
	tax
; Luetaan vihollisen Y-koordinaatti. VihY1=ylreuna, VihY2=alareuna.
	lda Sprite_vihkone1,x
	clc
	sbc #04
	sta VihY1,y
	lda Sprite_vihkone3,x
	clc
	adc #05
	sta VihY2,y
; Luetaan vihollisen X-koordinaatti. VihX1=vasen reuna, VihX2=oikea reuna.
	inx	; \
	inx	; | Spriten X-koordinaatti = perusosoite + 3.
	inx	; /
	lda Sprite_vihkone1,x
	clc
	sbc #12
	sta VihX1,y
	lda Sprite_vihkone2,x
	clc
	adc #08
	sta VihX2,y
; Silmukka.
	iny
	cpy MaxVihollisiaIlmassa
	bne VihKoordLukuLoop

; ========== LIIKUTA AMMUKSIA ==========

	lda #00
	sta AmmusLoopOsoitin	; Sislt numeron 0-19 riippuen ammuksesta.

AmmustenLiikutusSilmukka:

; Jos ammus ei liiku, ei tehd mitn.
	ldx AmmusLoopOsoitin
	lda #01
	cmp AmmustenTilat,x
	beq AmmusLiikkuu
	jmp AmmuksenLiikutusLoppu	; Liian kaukana, jotta BNE:t voisi kytt.
AmmusLiikkuu:

; X-rekisteriin liikutettavan spriten alkuosoite (AmmusLoopOsoitin * 4).
	lda AmmusLoopOsoitin
	asl a
	asl a
	tax
	stx AmmSprPerusOs

; Vhenn ammuksen Y-koordinaattia (perusosoite).
	dec AmmustenSpritet,x
	dec AmmustenSpritet,x
	dec AmmustenSpritet,x
	dec AmmustenSpritet,x

; Onko ammus mennyt ruudun ulkopuolelle?
	lda AmmustenSpritet,x		; Y-koordinaatti (perusosoite).
	cmp #02
	beq PoistaAmmus
	cmp #00
	beq PoistaAmmus
	jmp AmmusYhaRuudulla
PoistaAmmus:
	inx					; \ Tiili = spriten perusosoite + 1.
	lda #00				; | Tiilen numeroksi 00.
	sta AmmustenSpritet,x		; /
	ldx AmmusLoopOsoitin		; \ Ammuspaikka vapaaksi.
	lda #00				; |
	sta AmmustenTilat,x		; /
	jmp AmmuksenLiikutusLoppu
AmmusYhaRuudulla:

	ldy #00
AmmusOsunutViholliseenLoop:		; Tm silmukka on silmukan AmmustenLiikutusSilmukka sisll.
; Onko tutkittava vihollinen nyt ilmassa.
	lda VihIlmassa,y
	cmp #01
	beq VihollinenOnIlmassa
	jmp ViholliskoneTutkittu	; Kone ei ole ilmassa, joten sit ei tarvitse tutkia osumien varalta.
VihollinenOnIlmassa:
; Onko ammus Y-suunnassa viholliseen alareunan tasolla (tarkistus 5 pikselin kohdalla)
	lda VihY2,y			; \ Temp = vihollisen sijainti.
	sta Temp			; /
	ldx AmmSprPerusOs		; \ A = ammuksen sijainti.
	lda AmmustenSpritet,x	; /
	cmp Temp
	beq AmmYOK
	inc Temp
	cmp Temp
	beq AmmYOK
	inc Temp
	cmp Temp
	beq AmmYOK
	inc Temp
	cmp Temp
	beq AmmYOK
	inc Temp
	cmp Temp
	beq AmmYOK
	jmp ViholliskoneTutkittu
AmmYOK:
; Onko ammus X-suunnassa riittvn oikealla
	ldx AmmSprPerusOs
	inx
	inx
	inx
	lda AmmustenSpritet,x	; X-koordinaatti = perusosoite + 3.
	cmp VihX1,y
	bmi ViholliskoneTutkittu
; Onko ammus X-suunnassa riittvn vasemmalla
	lda AmmustenSpritet,x
	cmp VihX2,y
	bmi AmmusOsui
	jmp ViholliskoneTutkittu

; Ammus osui viholliseen.
AmmusOsui:
	lda VihDmg,y
	sta Temp		; Temp = vihollisella ennestn oleva vahinko.
	ldx AseenTeho	; AseenTeho-muuttujassa on 1, 2, 3 tai 4.
	dex
	lda AseenTehoToHitpoints,x	; A:ssa on nyt ammuksen tuottama vahinko.

	adc Temp		; A = A + Temp
	sta VihDmg,y	; Vihollisen vahinko = edellinen vahinko + uusi vahinko.

	cmp VihollisenKesto	; Onko riittvsti luoteja jo osunut.
	bmi TuotaOsumisAani	; Ei viel tuhoutunut, joten osumisni kuuluu.
	jsr PoistaVihollinen	; Tuhoutui. Y:ss vlitetn, mik vihollinen pit poistaa.
		lda #03	; niefekti 3: tuhoutumisni.
		jsr AaniEfekti

		lda AseenTeho		; Tuodaan ruudulle kerttv asevoimabonus.
		cmp #04
		beq PoistaOsunutAmmus		; Asevoima on jo maksimissa, joten sit ei voida en kasvattaa.

		asl a
		asl a
		inc VihollTuhottu
		cmp VihollTuhottu			; Vihollisia pit olla tuhottuna 4 * nykyinen aseen teho eli 4, 8 tai 12 kpl.
		bne PoistaOsunutAmmus		; Ei viel tarpeeksi vihollisia tuhottu, poistutaan.

		jsr NaytaAsevoimaBonus
		lda #00
		sta VihollTuhottu
	jmp PoistaOsunutAmmus
TuotaOsumisAani:
	lda #02	; niefekti 2: ammuksen osumisni.
	jsr AaniEfekti

PoistaOsunutAmmus:
; Poista viholliseen osunut ammus.
	ldx AmmusLoopOsoitin	; \
	lda #00			; | Ammuspaikka vapaaksi.
	sta AmmustenTilat,x	; /
	ldx AmmSprPerusOs		; \
	inx				; | Spriten tiili (perusosoite + 1) 00:ksi.
	lda #00			; |
	sta AmmustenSpritet,x	; /
ViholliskoneTutkittu:
; Silmukka.
	iny
	cpy MaxVihollisiaIlmassa
	beq VihollisOsumatTutkittu
	jmp AmmusOsunutViholliseenLoop
VihollisOsumatTutkittu:		; Ammus on tutkittu vihollisosumien varalta.

AmmuksenLiikutusLoppu:
; Kasvatetaan osoitinta kunnes kaikki 20 ammusta on liikutettu.
	inc AmmusLoopOsoitin
	ldx AmmusLoopOsoitin
	cpx #20
	beq AmmuksetLiikutettu
	jmp AmmustenLiikutusSilmukka
AmmuksetLiikutettu:

; ========== AMMUKSET ON LIIKUTETTU. LOPUT NMI-HRDELLIT. ==========

; Viholliskoneiden liikutus & tarkistus, onko nytn yllaidassa.
	ldy #00
OnkoKoneYlalaidLoop:
; Onko tutkittava vihollinen nyt ilmassa.
	lda VihIlmassa,y
	cmp #01
	beq VihollinenOnIlmassa2
	jmp VihollinenLiikutettu	; Kone ei ole ilmassa, joten sit ei tarvitse tutkia osumien varalta.
VihollinenOnIlmassa2:
; Kone on ehtinyt ruudun alalaitaan.
	lda VihY2,y
	cmp #00
	bne EiOleYlalaidassa
	jsr PoistaVihollinen			; Vihollisen numero vlittyy Y-rekisteriss.
	jmp VihollinenLiikutettu
EiOleYlalaidassa:
; X = Y * 4.
	tya
	asl a
	asl a
	tax

; Liikuta viholliskoneita pystysuunnassa.
	inc Sprite_vihkone1,x
	inc Sprite_vihkone2,x
	inc Sprite_vihkone3,x
	inc Sprite_vihkone4,x

; Liikuta viholliskoneita vaakasuunnassa.
	lda VihXSuunta,y
	inx	; \
	inx	; | Spriten X-koordinaatin vaihtamista varten.
	inx	; /

	cmp #02				; \ Oikealle?
	bne EiVihOikealle			; /
		; Liikuta vihollista oikealle.
		inc Sprite_vihkone1,x
		inc Sprite_vihkone2,x
		inc Sprite_vihkone3,x
		inc Sprite_vihkone4,x
		; Jos reunassa, vaihda suunta vasemmalle.
		lda Sprite_vihkone1,x
		cmp #241
		bne VihollinenLiikutettu
		lda #01
		sta VihXSuunta,y
		jmp VihollinenLiikutettu
	EiVihOikealle:
	cmp #01				; \ Vasemmalle?
	bne VihollinenLiikutettu	; /
		; Liikuta vihollista vasemmalle.
		dec Sprite_vihkone1,x
		dec Sprite_vihkone2,x
		dec Sprite_vihkone3,x
		dec Sprite_vihkone4,x
		; Jos reunassa, vaihda suunta oikealle.
		lda Sprite_vihkone1,x
		cmp #00
		bne VihollinenLiikutettu
		lda #02
		sta VihXSuunta,y

VihollinenLiikutettu:			; Silmukka.
	iny
	cpy MaxVihollisiaIlmassa
	beq VihollisetLiikutettu
	jmp OnkoKoneYlalaidLoop
VihollisetLiikutettu:


	; Testi: vihollisen liikutus vaakasuunnassa.
	;ldx #03
	;dec Sprite_vihkone1,x
	;dec Sprite_vihkone2,x
	;dec Sprite_vihkone3,x
	;dec Sprite_vihkone4,x

; Ovatko viholliskoneet trmnneet pelaajiin?
	ldy #00
VihollTormLoop:
; Onko tutkittava vihollinen nyt ilmassa.
	lda VihIlmassa,y
	cmp #01
	beq VihollinenOnIlmassa3
	jmp EiTormannyt		; Kone ei ole ilmassa, joten se ei varmasti ole trmnnyt pelaajaan.
VihollinenOnIlmassa3:
; Onko oma kone Y-suunnassa alempana kuin viholliskoneen ylraja.
	lda Sprite_omakone5
	cmp VihY1,y
	bmi EiTormannyt
; Onko oma kone Y-suunnassa ylempn kuin viholliskoneen alaraja.
	lda Sprite_omakone1
	cmp VihY2,y
	bpl EiTormannyt
; Onko oma kone X-suunnassa oikeammalla kuin viholliskoneen vasen raja.
	ldx #03
	lda Sprite_omakone2,x
	cmp VihX1,y
	bmi EiTormannyt
; Onko oma kone X-suunnassa vasemmammalla kuin viholliskoneen oikea raja.
	ldx #03
	lda Sprite_omakone1,x
	cmp VihX2,y
	bpl EiTormannyt
; niefekti (kohina).
	lda #03
	jsr AaniEfekti
	jmp GameOver	; Game Over!
EiTormannyt:
; Silmukka.
	iny
	cpy MaxVihollisiaIlmassa
	beq VihollTormTarkistettu
	jmp VihollTormLoop
VihollTormTarkistettu:


; Onko ilmassa bonus, jonka pelaaja voi ottaa?
	lda BonusIlmassa
	beq EiBonustaOtettu
; Onko oma kone Y-suunnassa alempana kuin bonus.
	lda Sprite_omakone5
	clc
	adc #05
	cmp Sprite_bonus
	bmi EiBonustaOtettu
; Onko oma kone Y-suunnassa ylempn kuin bonus.
	lda Sprite_omakone1
	clc
	sbc #05
	cmp Sprite_bonus
	bpl EiBonustaOtettu
; Onko oma kone X-suunnassa oikeammalla kuin bonus.
	ldx #03
	lda Sprite_omakone2,x
	clc
	adc #20
	cmp BonusX
	bmi EiBonustaOtettu
; Onko oma kone X-suunnassa vasemmammalla kuin bonus.
	ldx #03
	lda Sprite_omakone2,x
	clc
	sbc #05
	cmp BonusX
	bpl EiBonustaOtettu

	inc AseenTeho			; Pelaaja osui bonukseen.
	jsr PaivitaAsevoimaNaytto
	jsr PoistaAsevoimaBonus
	ldx AseenTeho			; Paranna tulitusnopeutta.
	dex
	lda AseenTehoToFiringrate,x
	sta FiringRate
; niefekti 4: bonuksen kerys.
	lda #04
	jsr AaniEfekti
EiBonustaOtettu:


; Tarkista, onko bonus ollut jo tarpeeksi kauan ilmassa.
	lda BonusIlmassa
	beq BonusTutkintaLoppu			; Ei edes ole ilmassa.
	inc Sprite_bonus
	lda Sprite_bonus
	cmp #$F0
	bne BonusTutkintaLoppu			; Ei ole viel ulkona ruudulta.
	jsr PoistaAsevoimaBonus			; Ulkona ruudulta, joten poistetaan.
; niefekti 5: bonuksen kerys myhstyi.
	lda #05
	jsr AaniEfekti
BonusTutkintaLoppu:

	jsr SiirraSpritedata		; Tmn pit ehdottomasti olla NMI-rutiinin lopussa.

	rti